#pragma once
#include <iostream>
#include <semaphore.h>
#include <vector>
#include<string>
#include <cassert>
#define _gcap 50
using namespace std;
void *P(sem_t &sem)
{
    int n = sem_wait(&sem);
    assert(n == 0);
    (void)n;
}
void *V(sem_t &sem)
{
    int n = sem_post(&sem);
    assert(n == 0);
    (void)n;
}
string PthreadSelf()
{
    char buffer[128];
    snprintf(buffer,sizeof buffer,"thread[0x%x]",pthread_self());
    return buffer;
}
template <class T>
class ringQueue
{
public:
    ringQueue(const int &cap = _gcap) : _queue(cap), _cap(cap), _spaceStep(0), _dataStep(0)
    {
        int n = sem_init(&_spaceSem, 0, _cap);
        assert(n == 0);
        n = sem_init(&_dataSem, 0, 0);
        assert(n == 0);
        n = pthread_mutex_init(&_plock,nullptr);
        assert(n==0);
        n = pthread_mutex_init(&_clock,nullptr);
        assert(n==0);
        (void)n;

    }
    ~ringQueue()
    {
        int n = sem_destroy(&_spaceSem);
        assert(n == 0);
        n = sem_destroy(&_dataSem);
        assert(n == 0);
        (void)n;
    }
    void Push(T &in)
    {
        P(_spaceSem); // 将_spacesSem--
        pthread_mutex_lock(&_plock);
        _queue[_spaceStep++] = in;
        _spaceStep %= _cap; // 当环形队列满了之后把指针位置改正
        pthread_mutex_unlock(&_plock);
        V(_dataSem);        // 将_dataSem++
    }
    void Pop(T *out)
    {
        P(_dataSem);
        pthread_mutex_lock(&_clock);
        *out = _queue[_dataStep];
        _queue[_dataStep++] = 0;
        _dataStep%= _cap;
        pthread_mutex_unlock(&_clock);
        V(_spaceSem);
    }

private:
    vector<T> _queue;
    sem_t _spaceSem;
    sem_t _dataSem;
    int _cap; // 环形队列的大小
    int _spaceStep;
    int _dataStep;
    pthread_mutex_t _plock;
    pthread_mutex_t _clock;
};